package com.blog.cloud.auth.service.impl;

import com.blog.cloud.api.dto.MobileLoginDto;
import com.blog.cloud.api.dto.NameLoginDto;
import com.blog.cloud.api.dto.UserInfoDto;
import com.blog.cloud.api.dto.UserRegisterDto;
import com.blog.cloud.api.entity.User;
import com.blog.cloud.api.feign.UserFeignService;
import com.blog.cloud.api.vo.auth.UserVO;
import com.blog.cloud.auth.service.AuthService;
import com.blog.cloud.captcha.service.CaptchaService;
import com.blog.cloud.core.exception.BlogException;
import com.blog.cloud.core.utils.BeanCopyUtil;
import com.blog.cloud.core.utils.R;
import com.blog.cloud.security.bo.UserInfo;
import com.blog.cloud.security.component.RedisTokenStore;
import com.blog.cloud.security.provider.MobileAuthenticationToken;
import com.blog.cloud.security.utils.JwtTokenUtil;
import com.blog.cloud.sms.service.SmsService;
import lombok.RequiredArgsConstructor;
import me.zhyd.oauth.model.AuthUser;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service("authService")
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final RedisTokenStore redisTokenStore;
    private final CaptchaService captchaService;
    private final UserFeignService userFeignService;
    private final SmsService tencentSmsService;
    private final AuthenticationManager authenticationManager;

    @Cacheable(cacheNames = "user:info")
    @Override
    public UserVO loginByUsername(NameLoginDto loginDto) {
        // 登录认证前先校验验证码
        Boolean result = captchaService.validate(loginDto.getKey(), loginDto.getCode());
        if (!result) {
            throw new BlogException("验证码错误");
        }

        Authentication authentication = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
        // 认证过后的Authentication对象中的principal就是我们封装返回的UserDetails对象
        Authentication authenticate = authenticationManager.authenticate(authentication);
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        String token = JwtTokenUtil.createToken(12345L);
        // Principal 即为封装的用户详细信息
        UserInfo userInfo = (UserInfo) authenticate.getPrincipal();
        // 判断用户角色，设置登陆过期时间
        userInfo.getRoles().forEach(role -> {
            if ("admin".equals(role)) {
                redisTokenStore.setUserInfo(token, userInfo, 60L, TimeUnit.MINUTES);
            } else if ("user".equals(role)) {
                redisTokenStore.setUserInfo(token, userInfo, 30L, TimeUnit.MINUTES);
            }
        });

        // 将一些用户基本信息和token返回给前端
        return new UserVO().setToken(token).setUserInfo(userInfo.getUserInfoVO());
    }

    @Override
    public UserVO loginByMobile(MobileLoginDto loginDto) {
        Authentication authentication = new MobileAuthenticationToken(loginDto.getMobile(), loginDto.getCode());
        Authentication authenticate = authenticationManager.authenticate(authentication);
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        String token = JwtTokenUtil.createToken(12345L);
        // Principal 即为封装的用户详细信息
        UserInfo userInfo = (UserInfo) authenticate.getPrincipal();
        // 判断用户角色，设置登陆过期时间
        userInfo.getRoles().forEach(role -> {
            if ("admin".equals(role)) {
                redisTokenStore.setUserInfo(token, userInfo, 60L, TimeUnit.MINUTES);
            } else if ("user".equals(role)) {
                redisTokenStore.setUserInfo(token, userInfo, 30L, TimeUnit.MINUTES);
            }
        });

        // 将一些用户基本信息和token返回给前端
        return new UserVO().setToken(token).setUserInfo(userInfo.getUserInfoVO());
    }

    @Override
    public Boolean register(UserRegisterDto registerDto) {
        if (Objects.isNull(registerDto)) {
            throw new BlogException("注册信息不能为空");
        }
        // 验证手机号的有效性，匹配短信验证码
        Boolean result = tencentSmsService.validate(registerDto.getMobile(), registerDto.getCode());
        if (!result) {
            throw new BlogException("短信验证码已失效");
        }

        R<User> response =  userFeignService.findUserByFlag(registerDto);
        if (Objects.nonNull(response.getData())) {
            throw new BlogException("该用户名或者手机号已被注册");
        }
        R<Boolean> flag = userFeignService.saveUser(registerDto);

        return flag.getData();
    }

    @Override
    public UserVO callBack(AuthUser authUser) {
        R<UserInfoDto> response = userFeignService.findUserByUsername(authUser.getUsername());
        // 如果是第一次进行授权登录，先根据用户名判断用户是否存在，如果不存在则注册一个，注册完之后登录认证
        if (Objects.isNull(response.getData())) {
            User user = BeanCopyUtil.singleCopy(authUser, User.class);
            user.setDescription(authUser.getRemark());
//            userFeignService.saveUser(user);
            // 进行认证
            R<UserInfoDto> userInfoDtoR = userFeignService.findUserByUsername(authUser.getUsername());

        }

        // 如果原先已经存在该用户，则直接封装信息返回
//        new UserVO().setUserInfo()
        return null;
    }
}
